//
//  Date+Extension.swift
//  SK_BasePrivateProject
//
//  Created by Regina on 2018/7/8.
//  Copyright © 2018年 leapp. All rights reserved.
//

import UIKit

extension Date {
    
    /// 该时间所在周的第一天日期
    var startOfWeek: Date {
        let calendar = NSCalendar.current
        let components = calendar.dateComponents(
            Set<Calendar.Component>([.yearForWeekOfYear, .weekOfYear]), from: self)
        return calendar.date(from: components)!
    }
    
    /// 该时间所在周的最后一天日期（如：2017年12月23日 00:00:00）
    var endOfWeek: Date {
        let calendar = NSCalendar.current
        var components = DateComponents()
        components.day = 6
        return calendar.date(byAdding: components, to: self.startOfWeek)!
    }
    
    /// 该时间所在周的最后一天日期（如：2017年12月23日 23:59:59）
    var endTimeOfWeek: Date {
        let calendar = NSCalendar.current
        var components = DateComponents()
        components.day = 7
        components.second = -1
        return calendar.date(byAdding: components, to: self.startOfWeek)!
    }
    
    
    ///获取日期具体组成（年、月、日、时、分、秒、 星期）,默认为当天
    func components() -> (year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int, weekday: Int) {
        let calendar = NSCalendar.current
        let com = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .weekday], from: self)
        return (com.year!, com.month!, com.day!, com.hour!, com.minute!, com.second!, com.weekday!)
    }
    
    ///当月天数
    func countOfDaysInMonth() -> Int {
        let calendar = Calendar(identifier:Calendar.Identifier.gregorian)
        let range = (calendar as NSCalendar?)?.range(of: NSCalendar.Unit.day, in: NSCalendar.Unit.month, for: self)
        return (range?.length)!
    }
    
    /// 当月第一天是星期几
    func firstWeekDay() -> Int {
        //1.Sun. 2.Mon. 3.Thes. 4.Wed. 5.Thur. 6.Fri. 7.Sat.
        let calendar = Calendar(identifier:Calendar.Identifier.gregorian)
        let firstWeekDay = (calendar as NSCalendar?)?.ordinality(of: NSCalendar.Unit.weekday, in: NSCalendar.Unit.weekOfMonth, for: self)
        return firstWeekDay! - 1
    }
    
    ///相差天数,默认与当天比较
    func dayDifference(fromDate: Date = Date()) -> Int {
        
        let timeInterval = self.timeIntervalSince(fromDate)
        let days = (Int(timeInterval)/(60*60*24))
        return days
    }
    
    ///相差月数,默认与当月比较
    func monthDifference(fromDate: Date = Date()) -> Int {
        
        let calendar = NSCalendar.current
        let comFrom = calendar.dateComponents([.year, .month], from: fromDate)
        let com = calendar.dateComponents([.year, .month,], from:self)
        return (com.year! - comFrom.year!)*12 + (com.month! -  comFrom.month!)
    }
    
    ///相差年数,默认与当年比较
    func yearDifference(fromDate: Date = Date()) -> Int {
        
        let calendar = NSCalendar.current
        let comFrom = calendar.dateComponents([.year, .month], from: fromDate)
        let com = calendar.dateComponents([.year, .month,], from:self)
        return com.year! - comFrom.year!
    }
    
    /**
     *  获取日期
     *
     *  @param  difference 相差天数
     *  @param  formatter  返回日期格式
     *
     *  @return 日期及日期字符串
     */
    func day(difference: Int, formatter: String = "yyyy-MM-dd") -> (date: Date, dateString: String) {
        
        let calendar = Calendar.init(identifier: Calendar.Identifier.gregorian)
        var dateComponents = DateComponents()
        dateComponents.day = difference;
        let date = calendar.date(byAdding: dateComponents, to: self)
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        
        let dateString = dateFormatter.string(from: date!)
        
        return (date!, dateString)
    }
    /**
     *  获取日期
     *
     *  @param  difference 相差月数
     *  @param  formatter  返回日期格式
     *
     *  @return 日期及日期字符串
     */
    func month(difference: Int, formatter: String = "yyyy-MM") -> (date: Date, dateString: String) {
        
        let calendar = Calendar.init(identifier: Calendar.Identifier.gregorian)
        var dateComponents = DateComponents()
        dateComponents.month = difference;
        let date = calendar.date(byAdding: dateComponents, to: self)
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        let dateString = dateFormatter.string(from: date!)

        return (date!, dateString)
    }
    /**
     *  获取日期
     *
     *  @param  difference 相差年数
     *  @param  formatter  返回日期格式
     *
     *  @return 日期及日期字符串
     */
    func year(difference: Int, formatter: String = "yyyy-MM") -> (date: Date, dateString: String) {
        
        let calendar = Calendar.init(identifier: Calendar.Identifier.gregorian)
        var dateComponents = DateComponents()
        dateComponents.year = difference;
        let date = calendar.date(byAdding: dateComponents, to: self)
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        let dateString = dateFormatter.string(from: date!)

        return (date!, dateString)
    }
    
    /// 昨天的日期
    ///
    /// - Returns: 日期及日期字符串
    func yesterday() -> (date: Date, dateString: String) {
        return self.day(difference: -1)
    }
    
    /// 明天的日期
    ///
    /// - Returns: 日期及日期字符串
    func tomorrow() -> (date: Date, dateString: String) {
        return self.day(difference: 1)
    }
    
    /// 某个时间段的开始和结束日期及对应的字符串
    typealias dateRangeTuple = (firstDate: Date, lastDate: Date, firstDateString: String, lastDateString: String)
    
    
    /// 指定日期对应周的开始和结束日期
    ///
    /// - Parameter date: 指定的日期
    /// - Returns: 日期及对应的字符串
    func startAndEndOfWeek(date: Date, dateFormat: String = "yyyy-MM-dd") -> dateRangeTuple {
        return (date.startOfWeek,
                date.endOfWeek,
                date.startOfWeek.toDateString(formatter: dateFormat),
                date.endOfWeek.toDateString(formatter: dateFormat))
    }
    
    /// 本周的开始和结束日期
    ///
    /// - Parameter dateFormat: 返回日期格式
    /// - Returns: 开始和结束日期及对应的字符串
    func currentWeek(dateFormat: String = "yyyy-MM-dd") -> dateRangeTuple {
        return self.startAndEndOfWeek(date: Date())
    }
    
    /// 指定日期的上一自然周的开始和结束日期
    ///
    /// - Parameter from: 指定的日期
    /// - Returns: 日期及对应的字符串
    func lastWeek(from: Date) -> dateRangeTuple {
        let calendar = NSCalendar.current
        var component = DateComponents()
        component.day = -7
        let oneDayOfLastWeek = calendar.date(byAdding: component, to: from)
        
        return self.startAndEndOfWeek(date: oneDayOfLastWeek!)
    }
    
    /// 指定日期的下一自然周的开始和结束日期
    ///
    /// - Parameter from: 指定的日期
    /// - Returns: 日期及对应的字符串
    func nextWeek(from: Date) -> dateRangeTuple {
        let calendar = Calendar.current
        var component = DateComponents()
        component.day = 7
        let oneDayOfLastWeek = calendar.date(byAdding: component, to: from)
        
        return self.startAndEndOfWeek(date: oneDayOfLastWeek!)
    }
    
    /// 月开始日期
    func startOfCurrentMonth() -> Date {
        let date = Date()
        let calendar = NSCalendar.current
        let components = calendar.dateComponents(
            Set<Calendar.Component>([.year, .month]), from: date)
        let startOfMonth = calendar.date(from: components)!
        return startOfMonth
    }
    
    /// 本月结束日期
    func endOfCurrentMonth(returnEndTime: Bool = false) -> Date {
        let calendar = NSCalendar.current
        var components = DateComponents()
        components.month = 1
        if returnEndTime {
            components.second = -1
        } else {
            components.day = -1
        }
        
        let endOfMonth =  calendar.date(byAdding: components, to: startOfCurrentMonth())!
        return endOfMonth
    }
    
    /// 指定年月的开始日期
    func startOfMonth(date: Date) -> Date {
        let calendar = NSCalendar.current
        var startComps = DateComponents()
        startComps.day = 1
        startComps.month = date.components().month
        startComps.year = date.components().year
        let startDate = calendar.date(from: startComps)!
        return startDate
    }
    
    /// 指定年月的结束日期
    func endOfMonth(date: Date,
                    returnEndTime: Bool = false) -> Date {
        let calendar = NSCalendar.current
        var components = DateComponents()
        components.month = 1
        if returnEndTime {
            components.second = -1
        } else {
            components.day = -1
        }
        
        let endOfYear = calendar.date(byAdding: components,
                                      to: startOfMonth(date: date))!
        return endOfYear
    }
    
    /// 当前月的开始和结束日期
    ///
    /// - Returns: 日期及对应的字符串
    func starAndEndOfCurrentMonth() -> dateRangeTuple {
        let dateFormat = "yyyy-MM-dd"
        return (startOfCurrentMonth(),
                endOfCurrentMonth(),
                startOfCurrentMonth().toDateString(formatter: dateFormat),
                endOfCurrentMonth().toDateString(formatter: dateFormat))
    }
    
    /// 指定日期对应月的开始和结束日期
    ///
    /// - Parameter date: 指定日期
    /// - Returns: 日期及对应的字符串
    func starAndEndOfMonth(date: Date) -> dateRangeTuple {
        let dateFormat = "yyyy-MM-dd"
        return (startOfMonth(date: date),
                endOfMonth(date: date),
                startOfMonth(date: date).toDateString(formatter: dateFormat),
                endOfMonth(date: date).toDateString(formatter: dateFormat))
    }
    
    /// 指定日期的上一个月的开始和结束日期
    ///
    /// - Parameter date: 指定日期
    /// - Returns: 日期及对应的字符串
    func lastMoth(date: Date) -> dateRangeTuple {
        let dateFormat = "yyyy-MM-dd"
        let start = startOfMonth(date: date)
        let yesterday = start.yesterday().date
        
        return (startOfMonth(date: yesterday),
                endOfMonth(date: yesterday),
                startOfMonth(date: yesterday).toDateString(formatter: dateFormat),
                endOfMonth(date: yesterday).toDateString(formatter: dateFormat))
    }
    
    /// 指定日期的下一个月的开始和结束日期
    ///
    /// - Parameter date: 指定日期
    /// - Returns: 日期及对应的字符串
    func nextMoth(date: Date) -> dateRangeTuple {
        let dateFormat = "yyyy-MM-dd"
        let end = endOfMonth(date: date)
        let tomorrow = end.tomorrow().date
        return (startOfMonth(date: tomorrow),
                endOfMonth(date: tomorrow),
                startOfMonth(date: tomorrow).toDateString(formatter: dateFormat),
                endOfMonth(date: tomorrow).toDateString(formatter: dateFormat))
    }
    
    ///将日期时间转为格式字符串
    func toDateString(formatter: String) -> String {
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        dateFormatter.timeZone = NSTimeZone.local
        let dateString = dateFormatter.string(from: self)
        return dateString
    }
    
    ///将时间字符串转为日期时间
    static func dateStringToDate(dateString: String, formatter: String) -> Date {
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        dateFormatter.timeZone = NSTimeZone.local
        let date = dateFormatter.date(from: dateString)
        return date!
    }
    
    ///时间转为时间戳
    func toTimeStamp() -> Int {
        return Int(self.timeIntervalSince1970);
    }
    
    
    
    ///时间戳转为日期时间
    static func timeStampToDate(timeStamp: String, formatter: String) -> (date: Date, dateString: String) {
        
        let timeSta:TimeInterval = NSString(string: timeStamp).doubleValue
        let date = Date(timeIntervalSince1970: timeSta)
        let dateFormatter = DateFormatter()
        
        dateFormatter.dateFormat = formatter
        
        let dateString = dateFormatter.string(from: date)
        return (date, dateString)
    }
    
    //月份数字转汉字
    static func monthToHanzi(monthNum: Int) -> String {
        let chinaArray = ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"]
        let chinaStr:String = chinaArray[monthNum - 1]
        return chinaStr
    }
}
